﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Web.Mvc;

namespace MvcContrib.Shp.UI.Menu
{
    /// <summary>
    /// Menu Item used for Controller-based navigation.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ActionMenuItem<T> : MenuItem where T : Controller
    {
        public ActionMenuItem(ViewContext viewContext, MenuSettings settings)
            : base(viewContext, settings)
        {
        }

        public Expression<Action<T>> MenuAction { get; set; }

        protected override bool IncludeItem()
        {
            return MenuAction != null && base.IncludeItem();
        }

        protected override void PrepareAttributes()
        {
            // set the url
            Url = !string.IsNullOrWhiteSpace(Url) ?
               Url :
               LinkBuilder.BuildUrlFromExpression(ViewContext.RequestContext, RouteTable.Routes, MenuAction);
            
            // get the configured Title attribute
            if (string.IsNullOrWhiteSpace(Title))
            {
                var attributes =
                    ((MethodCallExpression)(MenuAction.Body)).Method.GetCustomAttributes(typeof(MenuItemTitleAttribute), false);

                if (attributes.Length > 0)
                {
                    Title = ((MenuItemTitleAttribute)attributes[0]).Title;
                }
            }

            // get the configured Text attribute
            if (!DisplayText)
                Text = null;
            else
            {
                if (!string.IsNullOrWhiteSpace(Text))
                {
                    base.PrepareAttributes();
                    return;
                }

                var actionAttributes =
                    ((MethodCallExpression) (MenuAction.Body)).Method.GetCustomAttributes(
                        typeof (MenuItemTextAttribute), false);

                if (actionAttributes.Length > 0)
                {
                    Text = ((MenuItemTextAttribute) actionAttributes[0]).Text;
                    base.PrepareAttributes();
                    return;
                }

                var expression = (MenuAction.Body as MethodCallExpression);

                Text = expression != null
                           ? SplitPascalCase(expression.Method.Name)
                           : string.Empty;
            }

            base.PrepareAttributes();
        }

        /// <summary>
        /// Replaces pascal casing with spaces. For example "CustomerId" would become "Customer Id".
        /// Strings that already contain spaces are ignored.
        /// </summary>
        /// <param name="input">String to split</param>
        /// <returns>The string after being split</returns>
        protected virtual string SplitPascalCase(string input)
        {
            return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
        }

        public ActionMenuItem<T> SetMenuAction(Expression<Action<T>> menuAction)
        {
            MenuAction = menuAction;
            return this;
        }
    }
}
